﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI.WebControls;
using System.Web.Services;
using DocumentFormat.OpenXml.Math;
using Entidades.Models;
using Entidades;
using Controladores;
using Web.Extensions;
using Web.Handlers;
using Web.Helpers;
using Newtonsoft.Json;
using Entidades.Models.Sistema;
using Common;

namespace Web.Pages
{
    public partial class _Guion : BasePage
    {
        #region Private Members
        protected int _idProyecto;
        protected int _idGuion;
        #endregion

        #region Public Members
        #endregion

        #region Events

        protected new void Page_Load(object sender, EventArgs e)
        {
            try
            {
                base.Page_Load(sender, e);

                if (!Page.IsPostBack)
                {
                    _idProyecto = Helpers.WebHelper.Pages.QueryString.GetParameter<Int32>(Common.WellKnownKeys.Page.Parameters.ID_PROYECTO);
                    _idGuion    = Helpers.WebHelper.Pages.QueryString.GetParameter<Int32>(Common.WellKnownKeys.Page.Parameters.ID_GUION);

                    _idProyecto = _idProyecto == 0 ? Common.WellKnownKeys.Entities.DEFAULT_ID : _idProyecto;
                    _idGuion    = _idGuion == 0 ? Common.WellKnownKeys.Entities.DEFAULT_ID : _idGuion;

                    this.CargarPagina(_idProyecto, WellKnownKeys.Entities.TiposProyecto.SERIE.Id, _idGuion);
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        protected void rptGuionItems_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {

        }

        protected void rptGuionAutorizaciones_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {

        }

        #endregion

        #region Private Methods

        private void CargarPagina(int idProyecto, int idTipoProyecto, int idGuion)
        {
            try
            {
                var guion = default(Guion);

                if (idGuion != Common.WellKnownKeys.Entities.DEFAULT_ID)
                {
                    guion = new ControladorBase<Guion>().ObtenerEntidad(idGuion);
                    if (guion == null || guion.Activo == false)
                        SecurityHelper.RedirectUser(WellKnownKeys.Page.Names.PROYECTOS); // TODO => En MVC esto directamente debería arrojar una Exception o llevar a un 404, o algo así.
                }

                var tiposProyecto = TiposProyecto.ObtenerTodos();
                this.selGuion_TipoProyecto.Bind(tiposProyecto, "Id", "Texto");

                var proyectos = GetListInfo<Proyecto, ProyectoInfo>(x => x.Estudio.Id == base.CurrentStudio.Id && x.Tipo.Id == idTipoProyecto && x.Activo);
                this.selGuion_Proyecto.Bind(proyectos, "Id", "Texto");

                var estados = EstadosGuion.ObtenerTodos();
                var estadosPosibles = new int[]
                {
                    WellKnownKeys.Entities.EstadosGuion.GENERADO.Id,
                    WellKnownKeys.Entities.EstadosGuion.EN_GRABACION.Id,
                    WellKnownKeys.Entities.EstadosGuion.FINALIZADO.Id
                };
                estados = estados.Where(x => estadosPosibles.Contains(x.Id)).ToList();
                this.selGuion_Estado.Bind(estados, "Id", "Texto");
                
                var usuariosActores = new ControladorBase<Usuario>().ObtenerEntidades(x => x.Tipo.Id == Common.WellKnownKeys.Entities.TiposUsuario.ACTOR.Id);
                this.selGuion_UsuarioActor.Bind(usuariosActores, "Id", "Descriptor");

                var tiposCancion = TiposCancion.ObtenerTodos();
                this.selGuion_TipoCancion.Bind(tiposCancion, "Id", "Texto");
                
                var usuariosConVinculoActivo = ObtenerUsuariosConVinculoActivo(base.CurrentStudio.Id);
                
                #region Direccion / Traduccion / Adaptacion / Mezcla / Temporizador

                var noActores = usuariosConVinculoActivo.Where(x => x.Tipo.Id != WellKnownKeys.Entities.TiposUsuario.ACTOR.Id);

                var directores_y_operadores = new int[] { Common.WellKnownKeys.Entities.TiposUsuario.DIRECTOR.Id, Common.WellKnownKeys.Entities.TiposUsuario.OPERADOR.Id };
                var freelances = new int[] { Common.WellKnownKeys.Entities.CategoriasUsuario.FREELANCE.Id };

                var users_directores_y_operadores = usuariosConVinculoActivo.Where(x => directores_y_operadores.Contains(x.Tipo.Id));
                var users_directores_y_operadores_y_freelances = usuariosConVinculoActivo.Where(x => directores_y_operadores.Contains(x.Tipo.Id) || freelances.Contains(x.Categoria.Id));

                selGuion_Director.Bind(users_directores_y_operadores, "Id", "Descriptor");
                selGuion_Traductor.Bind(users_directores_y_operadores_y_freelances, "Id", "Descriptor");
                selGuion_Adaptador.Bind(users_directores_y_operadores_y_freelances, "Id", "Descriptor");
                selGuion_Mezclador.Bind(users_directores_y_operadores_y_freelances, "Id", "Descriptor");
                selGuion_Temporizador.Bind(noActores, "Id", "Descriptor");

                #endregion

                var estadosAutorizacion = new List<ListaInfo>
                {
                    new ListaInfo() {Id = 1, Texto = "Aprobada", Valor = 1},
                    new ListaInfo() {Id = 0, Texto = "Rechazada", Valor = 0}
                };
                this.selDialogAutorizaciones_Estado.Bind(estadosAutorizacion, "Id", "Texto");

                if (guion != null)
                {
                    this.CargarGuion(guion);
                    this.CargarCostos(guion, idTipoProyecto);
                    this.CargarImportacion(guion);
                    this.CargarAutorizaciones(guion);
                }
            }
            catch (Exception)
            {
                throw;
            }   
        }

        private void CargarGuion(Guion guion)
        {
            try
            {
                if (guion == null)
                    return;
                
                //if (guion.Estado.Id == Common.WellKnownKeys.Entities.EstadosGuion.GENERADO.Id && usuarioActual.Tipo.Id != Common.WellKnownKeys.Entities.TiposUsuario.MANAGER.Id)
                //    return;

                if (guion.Proyecto != null)
                {
                    this.selGuion_TipoProyecto.SetSelected(guion.Proyecto.Tipo.Id);
                    var proyectos = GetListInfo<Proyecto, ProyectoInfo>(x => x.Estudio.Id == base.CurrentStudio.Id && x.Tipo.Id == guion.Proyecto.Tipo.Id && x.Activo);
                    this.selGuion_Proyecto.Bind(proyectos, "Id", "Texto");
                    this.selGuion_Proyecto.SetSelected(guion.Proyecto.Id);
                }

                if (guion.Estado != null)
                {
                    this.selGuion_Estado.SetSelected(guion.Estado.Id);

                    if ( guion.TieneAutorizacionesPendientes() )
                    {
                        var estados = new int[]
                        {
                            WellKnownKeys.Entities.EstadosGuion.EN_GRABACION.Id,
                            WellKnownKeys.Entities.EstadosGuion.FINALIZADO.Id
                        };
                        this.selGuion_Estado.RemoveItems(estados);
                    }
                }

                if ( guion.Director != null )
                    this.selGuion_Director.SetSelected(guion.Director.Id);

                if ( guion.Traductor != null )
                    this.selGuion_Traductor.SetSelected(guion.Traductor.Id);
                
                if ( guion.Adaptador != null )
                    this.selGuion_Adaptador.SetSelected(guion.Adaptador.Id);
                
                if ( guion.Mezclador != null )
                    this.selGuion_Mezclador.SetSelected(guion.Mezclador.Id);

                if ( guion.Temporizador != null )
                    this.selGuion_Temporizador.SetSelected(guion.Temporizador.Id);

                this.txtGuion_Titulo.Value      = guion.Titulo;
                this.txtGuion_Episodio.Value    = guion.Episodio > 0 ? guion.Episodio.ToString() : string.Empty;
                this.txtGuion_Duracion.Value    = guion.Duracion.ToString();
                this.txtGuion_Personajes.Value  = guion.Personajes.ToString();
                this.txtGuion_Paginas.Value     = guion.Paginas.ToString();
                this.txtGuion_Loops.Value       = guion.Loops.ToString();
                this.txtGuion_Comentarios.Value = guion.Comentarios ?? String.Empty;

                #region Items

                this.rptGuionItems.DataSource = guion.Items;
                this.rptGuionItems.DataBind();

                #endregion

            }
            catch (Exception)
            {
                throw;
            }
        }

        private void CargarCostos(Guion guion, int idTipoProyecto)
        {
            GuionCosto costos = null;
            var gc = new GuionControlador();

            costos = guion != null
                ? gc.ObtenerCostoGuion(guion.Id)
                : gc.CopiarCostoMaestro(new ControladorBase<EstudioCosto>().ObtenerEntidad(x => x.TipoProyecto.Id == idTipoProyecto));

            if ( costos == null )
                costos = gc.CopiarCostoMaestro(new ControladorBase<EstudioCosto>().ObtenerEntidad(x => x.TipoProyecto.Id == idTipoProyecto));

            if ( costos != null )
            {
                this.txtGuion_Costos_Adaptacion.Value       = Common.Formatter.ToFixed(costos.Adaptacion);
                this.txtGuion_Costos_Cancion.Value          = Common.Formatter.ToFixed(costos.Cancion);
                this.txtGuion_Costos_Coro.Value             = Common.Formatter.ToFixed(costos.Coro);
                this.txtGuion_Costos_Direccion.Value        = Common.Formatter.ToFixed(costos.Direccion);
                this.txtGuion_Costos_LoopMinimo.Value       = Common.Formatter.ToFixed(costos.LoopMinimo);
                this.txtGuion_Costos_Loops.Value            = Common.Formatter.ToFixed(costos.Loops);
                this.txtGuion_Costos_Mezcla.Value           = Common.Formatter.ToFixed(costos.Mezcla);
                this.txtGuion_Costos_Palabras.Value         = Common.Formatter.ToFixed(costos.Palabras);
                this.txtGuion_Costos_Traduccion.Value       = Common.Formatter.ToFixed(costos.Traduccion);
                this.txtGuion_Costos_Temporizacion.Value    = Common.Formatter.ToFixed(costos.Temporizacion);
            }
        }

        private void CargarImportacion(Guion guion)
        {
            if (guion == null)
                return;

            var importacion = new ControladorBase<GuionImportacion>().ObtenerEntidad(x => x.Guion.Id == guion.Id);
            if ( importacion != null )
            {
                this.txtGuion_Importacion_Fecha.InnerHtml   = importacion.Fecha.ToDateAndTime();
                this.txtGuion_Importacion_Usuario.InnerHtml = importacion.Usuario.Descriptor;
                
                // TODO => try to avoid hardcoding !!!

                //this.txtGuion_Importacion_DOC.Value         = importacion.DOC;
                //this.txtGuion_Importacion_DOC.NavigateUrl   = Helpers.FileHelper.GetServerRoot() + Common.WellKnownKeys.Directories.Files.ScriptsUploaded + idGuion + "/" + importacion.DOC;
                this.txtGuion_Importacion_DOC.NavigateUrl   = String.Format( @"Handlers\DownloadFileHandler.ashx?downloadType={0}&idGuion={1}", (int)DownloadFileHandler.DownloadTypes.ScriptDoc, guion.Id );
                this.txtGuion_Importacion_DOC.Text          = importacion.DOC;
                this.txtGuion_Importacion_BRK.Value         = importacion.BRK;
                this.txtGuion_Importacion_STR.Value         = importacion.STR;
                //this.hdnGuion_Importacion_Directorio.Value  = Helpers.FileHelper.GetServerRoot() + Common.WellKnownKeys.Directories.Files.ScriptsUploaded + idGuion;
                this.hdnGuion_Importacion_Directorio.Value  = Common.WellKnownKeys.Directories.Files.ScriptsUploaded + guion.Id;
                this.lnkDescargarArchivos.HRef = String.Format( @"Handlers\DownloadFileHandler.ashx?downloadType={0}&idGuion={1}", (int)DownloadFileHandler.DownloadTypes.ScriptBundle, guion.Id );
            }
        }

        private void CargarAutorizaciones(Guion guion)
        {
            if (guion == null)
                return;

            this.rptGuionAutorizaciones.DataSource = guion.TransicionDeAutorizaciones;
            this.rptGuionAutorizaciones.DataBind();            
        }

        #endregion

        #region Web Methods

        /// <summary>
        /// Guarda los datos de un Guión
        /// </summary>
        /// <param name="infoGuion"></param>
        /// <param name="infoGuionItems"></param>
        /// <param name="infoGuionCosto"></param>
        /// <returns></returns>
        [WebMethod]
        public static string guardarGuion(string infoGuion, string infoGuionItems, string infoGuionCosto)
        {
            var mensaje     = string.Empty;
            var resultado   = false;
            object valor    = null;
            try
            {
                var idEstadoGuionFinalizado = WellKnownKeys.Entities.EstadosGuion.FINALIZADO.Id;
                var idEstadoGuionAnterior = WellKnownKeys.Entities.DEFAULT_ID;

                var controladorGuion = new ControladorBase<Guion>();
                var controladorGuionEstado = new ControladorBase<GuionEstado>();
                var controladorProyecto = new ControladorBase<Proyecto>();
                var controladorUsuario = new ControladorBase<Usuario>();

                var guionInfo = JsonConvert.DeserializeObject<GuionInfo>(infoGuion);

                var guionCostoInfo = JsonConvert.DeserializeObject<GuionCostoInfo>(infoGuionCosto);

                var fechaActual = DateTime.Now;
                var usuarioActual = SessionHelper.GetCurrentSessionInfo().User;

                var usuario = controladorUsuario.ObtenerEntidad(usuarioActual.Id);

                #region Guion
                var guion = controladorGuion.ObtenerEntidad( guionInfo.Id );
                if ( guion == null )
                    guion = new Guion();
                else
                    idEstadoGuionAnterior = guion.Estado != null ? guion.Estado.Id : WellKnownKeys.Entities.DEFAULT_ID;

                guion.Adaptador     = controladorUsuario.ObtenerEntidad( guionInfo.IdAdaptador );
                guion.Director      = controladorUsuario.ObtenerEntidad( guionInfo.IdDirector );
                guion.Mezclador     = controladorUsuario.ObtenerEntidad( guionInfo.IdMezclador );
                guion.Traductor     = controladorUsuario.ObtenerEntidad( guionInfo.IdTraductor );
                guion.Temporizador  = controladorUsuario.ObtenerEntidad( guionInfo.IdTemporizador );
                guion.Estado        = controladorGuionEstado.ObtenerEntidad( guionInfo.IdEstado );
                guion.Proyecto      = controladorProyecto.ObtenerEntidad( guionInfo.IdProyecto );
                guion.Duracion      = guionInfo.Duracion;
                guion.Loops         = guionInfo.Loops;
                guion.Paginas       = guionInfo.Paginas;
                guion.Personajes    = guionInfo.Personajes;
                guion.Titulo        = guionInfo.Titulo;
                guion.Episodio      = guionInfo.Episodio;
                guion.Comentarios   = guionInfo.Comentarios;
                guion.PendienteAutorizacion = guion.TieneAutorizacionesPendientes();
                #endregion

                #region Items del Guion

                var itemNuevo = false;
                var guionInfoItems = JsonConvert.DeserializeObject<List<GuionItemInfo>>(infoGuionItems);

                if ( guion.Items == null )
                    guion.Items = new List<GuionItem>();

                #region Eliminar items
                //Eliminar los ítems actuales que no se encuentran en la nueva lista..
                var itemsEliminados = new List<int>();
                foreach(var item in guion.Items)
                {
                    var infoItem = guionInfoItems.FirstOrDefault(x => x.Id == item.Id);
                    var existe = guionInfoItems.Contains( infoItem );
                    if ( !existe )
                        itemsEliminados.Add( item.Id );
                }
                foreach(var id in itemsEliminados)
                {
                    var item = guion.Items.FirstOrDefault(x => x.Id == id);
                    guion.Items.Remove( item );
                }
                #endregion

                #region Agregar/Actualizar items
                foreach (var itemInfo in guionInfoItems)
                {
                    var guionItem = guion.Items.FirstOrDefault(x => x.Id == itemInfo.Id);
                    //if ( guionItem != null )
                    //    guionItem = new GuionControlador().ObtenerGuionItem(guionItem.Id);

                    itemNuevo = false;
                    if ( guionItem == null )
                    {
                        guionItem = new GuionItem();
                        itemNuevo = true;
                    }

                    guionItem.Subtitulado       = itemInfo.Subtitulado;
                    guionItem.Actor             = controladorUsuario.ObtenerEntidad(itemInfo.IdActor);
                    guionItem.FechaGrabacion    = itemInfo.FechaGrabacion.HasValue? itemInfo.FechaGrabacion.Value : new DateTime?();
                    guionItem.Guion             = guion;
                    guionItem.Loops             = itemInfo.Loops;
                    guionItem.Personaje         = itemInfo.Personaje;
                    guionItem.TipoCancion       = new ControladorBase<TipoCancion>().ObtenerEntidad(itemInfo.IdTipoCancion);

                    if ( itemNuevo )
                        guion.Items.Add( guionItem );
                }

                #endregion

                #endregion

                #region Costo del Guion
                if ( guion.Costo == null )
                    guion.Costo = new GuionCosto();

                guion.Costo.Adaptacion      = guionCostoInfo.Adaptacion;
                guion.Costo.Cancion         = guionCostoInfo.Cancion;
                guion.Costo.Coro            = guionCostoInfo.Coro;
                guion.Costo.Direccion       = guionCostoInfo.Direccion;
                guion.Costo.Guion           = guion;
                //guion.Costo.Id            = guionCostoInfo.Id;
                guion.Costo.LoopMinimo      = guionCostoInfo.LoopMinimo;
                guion.Costo.Loops           = guionCostoInfo.Loops;
                guion.Costo.Mezcla          = guionCostoInfo.Mezcla;
                guion.Costo.Palabras        = guionCostoInfo.Palabras;
                guion.Costo.Traduccion      = guionCostoInfo.Traduccion;
                guion.Costo.Temporizacion   = guionCostoInfo.Temporizacion;
                #endregion

                #region Auditoria Guion
                if ( guion.UsuarioCreacion.IsNull() )
                    guion.UsuarioCreacion       = usuario;
                if ( guion.FechaCreacion.IsNull() || guion.FechaCreacion == DateTime.MinValue )
                {
                    guion.FechaCreacion         = fechaActual;
                }
                guion.UsuarioUltimaModificacion = usuario;
                guion.FechaUltimaModificacion   = fechaActual;
                if ( guion.Estado.Id == idEstadoGuionFinalizado )
                {
                    guion.UsuarioTerminacion    = usuario;
                    guion.FechaTerminacion      = fechaActual;
                }
                #endregion

                #region Transición de Estados
                GuionControlador.AgregarTransicionDeEstado(guion, guionInfo.IdEstado, fechaActual, usuarioActual.Id);
                #endregion

                resultado = controladorGuion.GuardarEntidad( guion );
                if ( resultado )
                {
                    mensaje = "Los datos del Guión fueron guardados exitosamente.";
                    valor = new GuionInfo(guion);

                    FacturacionHelper.ActualizarPagosDelGuion(guion);

                    var guionFueFinalizado = (idEstadoGuionAnterior != idEstadoGuionFinalizado) && (guion.Estado.Id == idEstadoGuionFinalizado);
                    if (guionFueFinalizado)
                    {
                        var resultadoEnvioMail = MailHelper.EnviarMailNotificacionGuionFinalizado(guion); 
                    }
                }
                else
                {
                    mensaje = "Hubo un error al intentar guardar los datos del Guión.";
                }
            }
            catch (Exception ex)
            {
                mensaje = "Hubo un error al intentar guardar los datos del Guión." + Environment.NewLine + ex.Message;
                LogError(ex);
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        /// <summary>
        /// Actualiza los datos de un Costo Maestro
        /// </summary>
        /// <param name="infoCostoMaestro"></param>
        /// <returns></returns>
        [WebMethod]
        public static string actualizarCostoMaestro(string infoCostoMaestro)
        {
            var mensaje  = string.Empty;
            var resultado  = false;
            object valor    = null;
            try
            {
                var costoMaestroInfo = JsonConvert.DeserializeObject<EstudioCostoInfo>(infoCostoMaestro);
                var cb = new ControladorBase<EstudioCosto>();

                var costo = cb.ObtenerEntidad(x => x.TipoProyecto.Id == costoMaestroInfo.IdTipoProyecto);
                if (costo.IsNotNull())
                {
                    costo.Adaptacion    = costoMaestroInfo.Adaptacion;
                    costo.Cancion       = costoMaestroInfo.Cancion;
                    costo.Coro          = costoMaestroInfo.Coro;
                    costo.Direccion     = costoMaestroInfo.Direccion;
                    costo.LoopMinimo    = costoMaestroInfo.LoopMinimo;
                    costo.Loops         = costoMaestroInfo.Loops;
                    costo.Mezcla        = costoMaestroInfo.Mezcla;
                    costo.Palabras      = costoMaestroInfo.Palabras;
                    costo.Traduccion    = costoMaestroInfo.Traduccion;
                    costo.Temporizacion = costoMaestroInfo.Temporizacion;

                    resultado = cb.GuardarEntidad( costo );
                }
                if ( resultado )
                {
                    mensaje = "Los valores del Maestro de Costos fueron actualizados exitosamente.";
                    valor = new EstudioCostoInfo(costo);
                }
                else
                {
                    mensaje = "Hubo un error al intentar actualizar el Maestro de Costos.";
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar actualizar el Maestro de Costos." + Environment.NewLine + ex.Message;
                LogError(ex);
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);        
        }

        /// <summary>
        /// Obtiene los datos de un Costo Maestro, según el Tipo de Proyecto
        /// </summary>
        /// <param name="idTipoProyecto"></param>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerCostoMaestro(int idTipoProyecto)
        {
            var mensaje     = "Hubo un error al intentar actualizar el Maestro de Costos.";
            var resultado   = false;
            object valor    = null;
            try
            {
                var costo = new ControladorBase<EstudioCosto>().ObtenerEntidad(x => x.TipoProyecto.Id == idTipoProyecto);
                if ( costo.IsNotNull() )
                {
                    resultado   = true;
                    mensaje     = "Los Costos fueron obtenidos exitosamente.";
                    valor       = new EstudioCostoInfo(costo);
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar obtener los Costos." + Environment.NewLine + ex.Message;
                LogError(ex);
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);        
        }

        /// <summary>
        /// Obtiene los Proyectos que corresponden a un Tipo de Proyecto dado
        /// </summary>
        /// <param name="idTipoProyecto"></param>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerProyectos(int idTipoProyecto)
        {
            var mensaje     = string.Empty;
            var resultado   = false;
            object valor    = null;
            try
            {
                var proyectos = new ControladorBase<Proyecto>().ObtenerEntidades(x => x.Tipo.Id == idTipoProyecto);
                if (proyectos.IsNotNull())
                {
                    mensaje = "Proyectos obtenidos exitosamente.";
                    resultado = true;
                    //valor = proyectos.Select(proyecto => new ProyectoInfo(proyecto)).ToList();
                    valor = proyectos.Select(x => new ListaInfo() {Id = x.Id, Valor = x.Id, Texto = x.Nombre}).ToList();
                }
            }
            catch (Exception ex)
            {
                mensaje = "Hubo un error al intentar obtener los Proyectos para el Tipo de Proyecto seleccionado." + Environment.NewLine + ex.Message;
                LogError(ex);
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }
        
        #endregion
    }
}